function states_ = gXmodality_statelist(varargin)

% arguments to make statelist polymorphic
if nargin < 7
    error('need 7 arguments')
else
    respond = varargin{1};
    up = varargin{2};
    down = varargin{3};
    left = varargin{4};
    right = varargin{5};
    targets = varargin{6};
    task = varargin(7);
end

% short viewing time
show = 300;

% short wait-for-response time
post = 350;

% confirm-or-modify-response time
hang = 100;

% start central fixation or jump to self-adjustment mode
acquire = { ...
    'dXkbHID',  {'f', 'ASLLEFT', 'j', 'ASLRIGHT'}; ...
    'dXPMDHID', {9, 'ASLLEFT', 11, 'ASLRIGHT'}; ...
    'dXasl',    {[1,true,inf], 'tone1', true}};

% maintain central fixation
fixate = { ...
    'dXkbHID',  {'any', 'error'}; ...
    'dXPMDHID', {'any', 'error'}; ...
    'dXasl',    {[1,false,inf], 'error', true}};

% self-adjustment mode for showing suspicious eye position
ASLLEFT = { ...
    'dXkbHID',  {'j', 'ASLGROUP'}; ...
    'dXPMDHID',	{11, 'ASLGROUP'}; ...
    'dXasl',    {}};
ASLRIGHT = { ...
    'dXkbHID',  {'f', 'ASLGROUP'}; ...
    'dXPMDHID',	{9, 'ASLGROUP'}; ...
    'dXasl',    {}};
ASL = { ...
    'dXkbHID',  {['f';'j'], 'ASLUNGROUP', true}; ...
    'dXPMDHID', {[9;11], 'ASLUNGROUP', true}; ...
    'dXasl',    {}};

% correct response depends on random stimulus
%   for dXlr, 0=left, 1=right
%   for dXdu, 0=down, 1=up
lcon = {'jump', {'dXlr', 1, 'value'}, [0 1], {'correct'; 'incorrect'}};
rcon = {'jump', {'dXlr', 1, 'value'}, [0 1], {'incorrect'; 'correct'}};
dcon = {'jump', {'dXdu', 1, 'value'}, [0 1], {'correct'; 'incorrect'}};
ucon = {'jump', {'dXdu', 1, 'value'}, [0 1], {'incorrect'; 'correct'}};

SP = @rPlay;
GS = @rGraphicsShow;
VU = @rVarUpdate;
Gr = @rGroup;

bp = 'dXbeep';
sd = 'dXsound';
ptrs = {'dXtc', 'dXquest', 'dXlr', 'dXdu'};
fp = {'dXtarget', 1};
stim = {'dXdots', 1};
noStim = {targets{:}, {}, 'dXdots', 1};
asl = {'gXASLCalibrate'};

%   name        fun args        jump    wait    repsDrawQuery   cond
arg_dXstate = {{ ...
    'indicate', GS, fp,         'next', 0,      0,  3,  0,      {}; ...
    'acquire',  {}, {},         'error',3e4,    0,  0   acquire,{}; ...
    'tone1',	SP, {bp,1},     'next', 100,	0,  0,  fixate,	{}; ...
    'nextStim',	VU, ptrs,       'next', 400,    0,  0,  1,      {}; ...
    'onStim',	GS, stim,       'next', 400,    0,  0,  1,      {}; ...
    'tone2',	SP, {bp,1},     'next', 100,	0,  0,  1,      {}; ...
    'showStim', {}, {},         'next', show,   0,  1,  1,      {}; ...
    'noStim',   GS, noStim,     'error',post,   0,  3,  respond,{}; ...
    ...
    'left',     {}, {},         'error',hang,	0,  0,  left,   lcon; ...
    'right',    {}, {},         'error',hang,	0,  0,  right,  rcon; ...
    'up',       {}, {},         'error',hang,	0,  0,  up,     ucon; ...
    'down',     {}, {},         'error',hang,	0,  0,  down,	dcon; ...
    'both',     {}, {},         'error',0,      0,  0,  0,      {}; ...
    ...
    'ASLLEFT',	{}, {},         'end',  500,	0,  0,  ASLLEFT,{}; ...
    'ASLRIGHT',	{}, {},         'end',  500,	0,  0,  ASLRIGHT,{}; ...
    'ASLGROUP', Gr, asl,        'next', 0,      0,  0,  0,      {}; ...
    'ASL',      {}, {},         'next', 2e6,    0,  3,  ASL,	{}; ...
    'ASLUNGROUP',Gr,task,       'end',  0,      0,  0,  0,      {}; ...
    ...
    'correct',  SP, {sd,1},     'end',  1000,   0,  0,  0,      {}; ...
    'incorrect',SP, {sd,2},     'end',  1000,   0,  0,  0,      {}; ...
    'error',    SP, {sd,3},     'next', 1000,   0,  5,  0,      {}; ...
    'end',      {}, {},         'x',    0,      0,  5,  0,      {}; ...
    }};
sz = size(arg_dXstate{1}, 1);

tony = {'current', true, true, false};
states_ = {'dXstate', sz, tony, arg_dXstate};